/**
 *  StackFrame.java : IceBird project
 *  14:41:16 
 */
package icebird.compiler.ncomp;

import icebird.metadata.Method;

/**
 * @author Sergey Shulepoff[Knott]
 */
public final class StackFrame {

	private Label footer;
	
	private X86Assembler asm;
	private Method m;
	
	private boolean isOpenNeeded() {
		CallConv conv = m.getCallConv();
		
		if (conv == CallConv.STD_CALL) { 
			if (m.getCode() == null) return true;
			
			if (m.getLocalsCount() > 0) {
				return true;
			} else return false;
		}
		else if (conv == CallConv.PURE_REGISTER) return false;
		else if (conv == CallConv.FAST_CALL) {
			if (m.getArguments().length > 2) return true;
			else return false;
		} else if (conv == CallConv.NATIVE_CALL) {
			// Needed to open.
			return true;
		} else {
			throw new RuntimeException("Unknown calling conversion");
		}
	}
	
	public StackFrame(Method m) {
		asm = X86Assembler.getAsm();
		footer = new Label(".footer");
		this.m = m;
	}
	
	/**
	 * Emit prolog.
	 * @return void
	 */
	public void emitHeader() {
		if (!isOpenNeeded()) return;
		
		asm.push(X86Register.EBP);
		asm.move(X86Register.EBP, X86Register.ESP);
		
		if (m.getLocalsCount() != 0) {
			asm.sub(X86Register.ESP, (m.getLocalsCount() * 4) + 4);
		}
	}
	
	/**
	 * Emit epilog.
	 * @return void
	 */
	public void emitTrailer() {
		asm.bind(footer);
		
		if (!isOpenNeeded()) {
			asm.ret();
			return;
		}
		
		if (m.getLocalsCount() != 0) {
			asm.add(X86Register.ESP, (m.getLocalsCount() * 4) + 4);
		}
		
		asm.move(X86Register.ESP, X86Register.EBP);
		asm.pop(X86Register.EBP);
		
		asm.ret();
	}
	
	public void emitReturn() {
		asm.jmp(footer);
	}
}
